import base64
import hashlib
import os
import sys
import traceback
import time
from flask import Flask, request, send_from_directory, g
from flask_cors import CORS
from flask_jwt_extended import JWTManager, jwt_required
from datetime import datetime, timedelta
from libs.conn import *
from libs.utils import *
from libs.global_thread import global_process

from api.login import login_bp
from api.cmds import cmds_bp
from api.clients import clients_bp
from api.lanips import lanips_bp
from api.tasks import tasks_bp
from api.logs import logs_bp
from api.system_logs import system_logs_bp
from api.alarm_notices import alarm_notices_bp
from api.alarm_plans import alarm_plans_bp
from api.alarm_records import alarm_records_bp
from api.apps import apps_bp
from api.configs import configs_bp
from api.detection_values import detection_values_bp

# 初始化数据库
init_db()
# 创建目录
if not os.path.exists(log_dir):
    os.makedirs(log_dir)
if not os.path.exists(export_dir):
    os.makedirs(export_dir)

app = Flask(__name__)
app.secret_key = 'th1sIsas3cretk5y'  # 用于会话加密
CORS(app)  # 允许跨域请求，默认允许所有来源的所有请求方法
app.config['JWT_SECRET_KEY'] = 'th1sIsas3cretk5y'  # 设置密钥
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(minutes=120)  # 设置有效期为 120 分钟
jwt = JWTManager(app)

# 注册蓝图
app.register_blueprint(login_bp)
app.register_blueprint(cmds_bp)
app.register_blueprint(clients_bp)
app.register_blueprint(lanips_bp)
app.register_blueprint(tasks_bp)
app.register_blueprint(logs_bp)
app.register_blueprint(system_logs_bp)
app.register_blueprint(alarm_notices_bp)
app.register_blueprint(alarm_plans_bp)
app.register_blueprint(alarm_records_bp)
app.register_blueprint(apps_bp)
app.register_blueprint(configs_bp)
app.register_blueprint(detection_values_bp)

# 设置请求前和请求后的钩子
@app.before_request
def before_request():
    # 存储请求信息
    g.request_info = {
        'method': request.method,
        'path': request.path,
        'start_time': time.time()
    }

@app.after_request
def after_request(response):
    # 计算请求耗时
    duration = (time.time() - g.request_info['start_time']) * 1000
    g.request_info['duration'] = f"{duration:.2f}ms"
    g.request_info['status'] = response.status_code
    # 记录请求日志，拼接请求信息和响应信息为日志记录形式
    # 将start_time这种float数值格式化为时间字符串格式
    start_time = datetime.fromtimestamp(g.request_info['start_time']).strftime('%Y-%m-%d %H:%M:%S')
    write_log_to_file(os.path.join(log_dir, 'access.log'), f"{request.remote_addr} [{start_time}] {g.request_info['method']} {g.request_info['path']} {g.request_info['duration']} {g.request_info['status']}")
    return response


# 错误处理
@app.errorhandler(Exception)
def handle_exception(e):
    # 记录错误堆栈，包含错误信息和堆栈跟踪
    log_error(f"Exception: {str(e)}\n{traceback.format_exc()}")
    # 返回错误响应
    return { 'status': 'error', 'msg': str(e) }, 500


# 如下为静态文件
@app.route('/client_monitor.sh', methods=['GET'])
def client_monitor_sh():
    return send_from_directory(os.path.dirname(__file__), "client_monitor.sh")

@app.route('/exports/<filename>')
@jwt_required()
def export_file(filename):
    return send_from_directory(export_dir, filename, as_attachment=True)

@app.route('/')
def index():
    return send_from_directory(os.path.join(os.path.dirname(__file__), "web/dist"), "index.html")

@app.route('/login')
def index_login():
    return send_from_directory(os.path.join(os.path.dirname(__file__), "web/dist"), "index.html")

@app.route('/<path:filename>')
def download_file(filename):
    return send_from_directory(os.path.join(os.path.dirname(__file__), 'web/dist'), filename, as_attachment=True)


# 如下为客户端的API请求接口
@app.route('/test')
def test():
    # 处理请求参数
    client_id = request.args.get('client_id')
    cmd_id = request.args.get('cmd_id')
    msg = request.args.get('msg')
    if msg != None and msg != '':
        msg = msg.replace(' ', '+')
        msg = base64.b64decode(msg.encode('utf-8')).decode('utf-8')

    # 记录设备登录状态，查询clients表中是否存在具有指定client_id的记录
    client_secret = ''
    row = fetchone("SELECT client_id, client_secret FROM clients WHERE client_id = ?", (client_id,))
    if row is None:
        execute("INSERT INTO clients (client_id, client_ip, client_alive_time) VALUES (?, ?, ?)", (client_id, get_ip(), get_time()))
    else:
        if row['client_secret'] is not None:
            client_secret = row['client_secret']
        execute("UPDATE clients SET client_alive_time = ? WHERE client_id = ?", (get_time(), client_id))

    # 处理消息
    response_status = 1
    response_msg = ''
    response_cmd_id = 0
    response_cmd = generate_random_string()
    

    if cmd_id == '-1': # 日志
        log_info(client_id + " 日志消息：" + msg)
        # 将日志信息插入到数据库中
        logs = msg.strip('\n').split('\n')
        for log in logs:
            execute("INSERT INTO logs (client_id, log_content, log_time) VALUES (?, ?, ?)", (client_id, log, get_time()))
    elif cmd_id == '-2': # 时间同步
        log_info(client_id + " 首次登录" + msg)
        response_msg = base64.b64encode(get_time().encode('utf-8')).decode('utf-8')
    elif cmd_id == '-3': # 注册，将密钥主动发送给服务器
        log_info(client_id + " 注册消息：" + msg)
        client_secret = msg
        execute("UPDATE clients SET client_secret = ? WHERE client_id = ?", (msg, client_id))
    elif cmd_id == '-4': # 局域网信息，返回信息中包括在线设备的lanip_id和是否在线
        log_info(client_id + " 局域网信息：" + msg)
        temp = msg.strip().split('_')
        client_lanips_md5 = temp[0]
        if len(temp) > 1:
            lanip_ids = temp[1].strip('-').split('-')
            current_time = get_time()
            for lanip_id in lanip_ids:
                execute("UPDATE lanips SET lanip_alive_time = ? WHERE lanip_id = ? and client_id = ?", (current_time, lanip_id, client_id))
        # 然后通过md5判断客户端的局域网IP列表与本地是否一致，如果不一致则更新客户端列表
        rows = fetchall("SELECT * FROM lanips WHERE client_id = ? and lanip_enable = 1", (client_id,))
        if len(rows) > 0:
            lanips_str = '\n'.join([ str(row['lanip_id'])+','+row['lanip_ip'] for row in rows ])
        else:
            lanips_str = '0' # 没有局域网IP
        lanips_md5 = hashlib.md5(lanips_str.encode('utf-8')).hexdigest()
        if lanips_md5 != client_lanips_md5:
            response_msg = base64.b64encode(lanips_str.encode('utf-8')).decode('utf-8')
    else: # 指令
        # 从数据库中根据cmd_id写入result，并将complete字段设置为1
        execute("UPDATE cmds SET result = ?, complete = 1, result_time = ? WHERE cmd_id = ?", (msg, get_time(), cmd_id))
        log_info(client_id + " 已执行指令结果：" + cmd_id + ' ' + msg)

    # 从数据库中取指令
    row = fetchone("SELECT * FROM cmds WHERE client_id = ? AND complete = 0 ORDER BY cmd_id ASC LIMIT 1", (client_id,))
    if row is not None:
        response_cmd_id = row['cmd_id']
        response_cmd = row['cmd']

    check_value = hash_message(response_cmd, client_secret)
    response_cmd = base64.b64encode(response_cmd.encode('utf-8')).decode('utf-8')
    result = "{},{},{},{},{}".format(response_status, response_msg, response_cmd_id, response_cmd, check_value)
    return result


if __name__ == '__main__':
    global_process() # 开启全局进程，一分钟执行一次
    port = 8888
    if len(sys.argv) > 1:
        port = int(sys.argv[1])
    app.run("0.0.0.0", port=port, debug=False)

